﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DOTNET101_UnsafeCode_Pointers
{
    class Program
    {
        public struct MyArray
        {
            public char[] pathName;
            private int reserved;
        }

        public struct MyArray1 // This code must appear in an unsafe block
        {
            unsafe public fixed char pathName[128];
        }

        static void Main(string[] args)
        {
        }
    }

    class FileReader
    {
        const uint GENERIC_READ = 0x80000000;
        const uint OPEN_EXISTING = 3;
        System.IntPtr handle;

        [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
        static extern unsafe System.IntPtr CreateFile
        (
            string FileName,          // file name
            uint DesiredAccess,       // access mode
            uint ShareMode,           // share mode
            uint SecurityAttributes,  // Security Attributes
            uint CreationDisposition, // how to create
            uint FlagsAndAttributes,  // file attributes
            int hTemplateFile         // handle to template file
        );

        [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
        static extern unsafe bool ReadFile
        (
            System.IntPtr hFile,      // handle to file
            void* pBuffer,            // data buffer
            int NumberOfBytesToRead,  // number of bytes to read
            int* pNumberOfBytesRead,  // number of bytes read
            int Overlapped            // overlapped buffer
        );

        [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
        static extern unsafe bool CloseHandle
        (
            System.IntPtr hObject // handle to object
        );

        public bool Open(string FileName)
        {
            // open the existing file for reading       
            handle = CreateFile
            (
                FileName,
                GENERIC_READ,
                0,
                0,
                OPEN_EXISTING,
                0,
                0
            );

            if (handle != System.IntPtr.Zero)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public unsafe int Read(byte[] buffer, int index, int count)
        {
            int n = 0;
            fixed (byte* p = buffer)
            {
                if (!ReadFile(handle, p + index, count, &n, 0))
                {
                    return 0;
                }
            }
            return n;
        }

        public bool Close()
        {
            return CloseHandle(handle);
        }
    }

    class TestReadFile
    {
        public static int Test(string[] args)
        {
            if (args.Length != 1)
            {
                System.Console.WriteLine("Usage : ReadFile <FileName>");
                return 1;
            }

            if (!System.IO.File.Exists(args[0]))
            {
                System.Console.WriteLine("File " + args[0] + " not found.");
                return 1;
            }

            byte[] buffer = new byte[128];
            FileReader fr = new FileReader();

            if (fr.Open(args[0]))
            {
                // Assume that an ASCII file is being read.
                System.Text.ASCIIEncoding Encoding = new System.Text.ASCIIEncoding();

                int bytesRead;
                do
                {
                    bytesRead = fr.Read(buffer, 0, buffer.Length);
                    string content = Encoding.GetString(buffer, 0, bytesRead);
                    System.Console.Write("{0}", content);
                }
                while (bytesRead > 0);

                fr.Close();
                return 0;
            }
            else
            {
                System.Console.WriteLine("Failed to open requested file");
                return 1;
            }
        }
    }

    class TestUnsafeCopy
    {
        // The unsafe keyword allows pointers to be used within the following method:
        static unsafe void Copy(byte[] src, int srcIndex, byte[] dst, int dstIndex, int count)
        {
            if (src == null || srcIndex < 0 ||
                dst == null || dstIndex < 0 || count < 0)
            {
                throw new System.ArgumentException();
            }

            int srcLen = src.Length;
            int dstLen = dst.Length;
            if (srcLen - srcIndex < count || dstLen - dstIndex < count)
            {
                throw new System.ArgumentException();
            }

            // The following fixed statement pins the location of the src and dst objects
            // in memory so that they will not be moved by garbage collection.
            fixed (byte* pSrc = src, pDst = dst)
            {
                byte* ps = pSrc;
                byte* pd = pDst;

                // Loop over the count in blocks of 4 bytes, copying an integer (4 bytes) at a time:
                for (int i = 0; i < count / 4; i++)
                {
                    *((int*)pd) = *((int*)ps);
                    pd += 4;
                    ps += 4;
                }

                // Complete the copy by moving any bytes that weren't moved in blocks of 4:
                for (int i = 0; i < count % 4; i++)
                {
                    *pd = *ps;
                    pd++;
                    ps++;
                }
            }
        }

        public static void Test()
        {
            byte[] a = new byte[100];
            byte[] b = new byte[100];

            for (int i = 0; i < 100; ++i)
            {
                a[i] = (byte)i;
            }

            Copy(a, 0, b, 0, 100);
            System.Console.WriteLine("The first 10 elements are:");

            for (int i = 0; i < 10; ++i)
            {
                System.Console.Write(b[i] + " ");
            }
            System.Console.WriteLine("\n");
        }
    }
}

///
///
namespace N  // "N:N"
{
    ///
    ///
    public unsafe class X    // "T:N.X"
    {
        public X() { }
        //----------------------------
        // The result of the above is:
        // "M:N.X.#ctor"


        /// <param name="i"></param>
        public X(int i) { }
        //----------------------------
        // The result of the above is:
        // "M:N.X.#ctor(System.Int32)"


        ~X() { }
        //----------------------------
        // The result of the above is:
        // "M:N.X.Finalize", destructor's representation in metadata


        public string q;
        //----------------------------
        // The result of the above is:
        // "F:N.X.q"


        /// <returns></returns>
        public const double PI = 3.14;
        //----------------------------
        // The result of the above is:
        // "F:N.X.PI"


        /// <param name="s"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public int f() { return 1; }
        //----------------------------
        // The result of the above is:
        // "M:N.X.f"


        /// <param name="array1"></param>
        /// <param name="array"></param>
        /// <returns></returns>
        public int bb(string s, ref int y, void* z) { return 1; }
        //----------------------------
        // The result of the above is:
        // "M:N.X.bb(System.String,System.Int32@,=System.Void*)"


        /// <param name="x"></param>
        /// <param name="xx"></param>
        /// <returns></returns>
        public int gg(short[] array1, int[,] array) { return 0; }
        //----------------------------
        // The result of the above is:
        // "M:N.X.gg(System.Int16[], System.Int32[0:,0:])"


        public static X operator +(X x, X xx) { return x; }
        //----------------------------
        // The result of the above is:
        // "M:N.X.op_Addition(N.X,N.X)"


        public int prop { get { return 1; } set { } }
        //----------------------------
        // The result of the above is:
        // "P:N.X.prop"


        public event D d;
        //----------------------------
        // The result of the above is:
        // "E:N.X.d"


        public int this[string s] { get { return 1; } }
        //----------------------------
        // The result of the above is:
        // "P:N.X.Item(System.String)"


        public class Nested { }
        //----------------------------
        // The result of the above is:
        // "T:N.X.Nested"


        public delegate void D(int i);
        //----------------------------
        // The result of the above is:
        // "T:N.X.D"


        /// <param name="x"></param>
        /// <returns></returns>
        public static explicit operator int(X x) { return 1; }
        //----------------------------
        // The result of the above is:
        // "M:N.X.op_Explicit(N.X)~System.Int32"
    }

    // compile with: /doc:DocFileName.xml 

    /// <summary>
    /// Class level summary documentation goes here.</summary>
    /// <remarks>
    /// Longer comments can be associated with a type or member 
    /// through the remarks tag</remarks>
    public class TestClass
    {
        /// <summary>
        /// Store for the name property</summary>
        private string _name = null;

        /// <summary>
        /// The class constructor. </summary>
        public TestClass()
        {
            // TODO: Add Constructor Logic here
        }

        /// <summary>
        /// Name property </summary>
        /// <value>
        /// A value tag is used to describe the property value</value>
        public string Name
        {
            get
            {
                if (_name == null)
                {
                    throw new System.Exception("Name is null");
                }
                return _name;
            }
        }

        /// <summary>
        /// Description for SomeMethod.</summary>
        /// <param name="s"> Parameter description for s goes here</param>
        /// <seealso cref="System.String">
        /// You can use the cref attribute on any tag to reference a type or member 
        /// and the compiler will check that the reference exists. </seealso>
        public void SomeMethod(string s)
        {
        }

        /// <summary>
        /// Some other method. </summary>
        /// <returns>
        /// Return results are described through the returns tag.</returns>
        /// <seealso cref="SomeMethod(string)">
        /// Notice the use of the cref attribute to reference a specific method </seealso>
        public int SomeOtherMethod()
        {
            return 0;
        }
    }
}